//使用常量来使调用提示比较方便有提示
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"


class MyPromis {
    constructor(executor) {
        //捕获执行器执行时发生错误
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }

    }

    status = PENDING
    //使用箭头函数防止调用时更改this指向
    value = undefined//成功的值
    reason = undefined//失败的值
    successCallback = [] //成功的处理函数
    failCallback = [] //失败的处理函数
    resolve = (value) => {
        //防止状态被随意改变
        if (this.status !== PENDING) return
        this.status = FULFILLED
        this.value = value//成功参数保存
        //保证多次调用顺序执行
        while (this.successCallback.length) this.successCallback.shift()()
    }
    reject = (reason) => {
        //防止状态被随意改变
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.reason = reason//失败参数保存
        //保证多次调用顺序执行
        while (this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        //then参数的可选实现
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason }

        //让then方法可以返回promise对象实现链式调用
        let promise2 = new MyPromis((resolve, reject) => {
            //.then执行方法的判断
            if (this.status == FULFILLED) {
                setTimeout(() => {
                    try {
                        //防止自己返回自己循环调用使用延时器变成异步代码正常获取promise2
                        let success = successCallback(this.value)
                        //保证链式调用中将参数正确传入至下一个then方法中
                        //根据success的值的类型进行判断
                        resolvePromise(promise2, success, resolve, reject)
                    } catch (error) {
                        reject(error)
                        //将错误传递给下一个then方法
                    }
                }, 0)

            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        //防止自己返回自己循环调用使用延时器变成异步代码正常获取promise2
                        let reason = failCallback(this.reason)
                        //保证链式调用中将参数正确传入至下一个then方法中
                        //根据success的值的类型进行判断
                        resolvePromise(promise2, reason, resolve, reject)
                    } catch (error) {
                        reject(error)
                        //将错误传递给下一个then方法
                    }
                }, 0)
            } else {
                //处理异步等待逻辑,存储成功和失败处理逻辑
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //防止自己返回自己循环调用使用延时器变成异步代码正常获取promise2
                            let success = successCallback(this.value)
                            //保证链式调用中将参数正确传入至下一个then方法中
                            //根据success的值的类型进行判断
                            resolvePromise(promise2, success, resolve, reject)
                        } catch (error) {
                            reject(error)
                            //将错误传递给下一个then方法
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //防止自己返回自己循环调用使用延时器变成异步代码正常获取promise2
                            let reason = failCallback(this.reason)
                            //保证链式调用中将参数正确传入至下一个then方法中
                            //根据success的值的类型进行判断
                            resolvePromise(promise2, reason, resolve, reject)
                        } catch (error) {
                            reject(error)
                            //将错误传递给下一个then方法
                        }
                    }, 0)
                })
            }
        })

        return promise2
    }

    static all(arr) {
        let count = 0
        let result = [];

        return new MyPromis((resolve, reject) => {
            function addData(i, value) {
                result[i] = value
                count++
                //此处放置异步对象未处理完成时就结束循环
                if (count === arr.length) {
                    resolve(result)
                }
            }
            arr.forEach((el, index) => {
                if (el instanceof MyPromis) {
                    el.then(value => addData(index, value), reason => reject(reason))
                } else {
                    addData(index, el)
                }

            });

        })
    }
    static resolve(values) {
        if (values instanceof MyPromis) return values
        return new MyPromis(resolve => resolve(values))
    }
    finally(cb) {
        return this.then(value => {
            return MyPromis.resolve(cb()).then(() => value)

        }, reason => {
            return MyPromis.resolve(cb()).then(() => { throw reason })
        })

    }

    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
}


function resolvePromise(promise, x, resolve, reject) {
    if (promise === x) {
        reject(new TypeError("循环调用了promise"))
    }



    if (x instanceof MyPromis) {
        //promise对象
        x.then(resolve, reject)
    } else {
        //非promise对象直接调用resolve
        resolve(x)
    }
}